﻿using System;
using System.Xml;
using System.ServiceModel.Security;
using System.IdentityModel.Tokens;
using System.IdentityModel.Selectors;

namespace Sinacor.Infra.Common.Security.Authentication.Credentials
{
    public class SinacorTokenSerializer : WSSecurityTokenSerializer
    {
        public SinacorTokenSerializer(SecurityTokenVersion version) : base() { }

        protected override bool CanReadTokenCore(XmlReader reader)
        {
            XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader);
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }
            if (reader.IsStartElement(Constants.SinacorTokenName, Constants.SinacorTokenNamespace))
            {
                return true;
            }
            return base.CanReadTokenCore(reader);
        }

        protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }
            if (reader.IsStartElement(Constants.SinacorTokenName, Constants.SinacorTokenNamespace))
            {
                string id = reader.GetAttribute(Constants.Id, Constants.WsUtilityNamespace);
                Int32? sessionId = null;
                reader.ReadStartElement();

                // Read the informations
                string companyId = reader.ReadElementString(Constants.CompanyIdElementName, Constants.SinacorTokenNamespace);
                string password = reader.ReadElementString(Constants.PasswordElementName, Constants.SinacorTokenNamespace);
                string userName = reader.ReadElementString(Constants.UserNameElementName, Constants.SinacorTokenNamespace);
                string stTokenId = reader.ReadElementString(Constants.TokenIdElementName, Constants.SinacorTokenNamespace);
                string stSessionId = reader.ReadElementString(Constants.SessionIdElementName, Constants.SinacorTokenNamespace);
                string stSessionExpires = reader.ReadElementString(Constants.SessionExpiresElementName, Constants.SinacorTokenNamespace);
                
                reader.ReadEndElement();

                if (!String.IsNullOrEmpty(stSessionId))
                    sessionId = int.Parse(stSessionId);

                SinacorUserInfo userInfo = new SinacorUserInfo(userName, password, int.Parse(companyId), sessionId, stTokenId,bool.Parse(stSessionExpires));

                return new SinacorToken(userInfo,id);
            }
            else
            {
                return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, tokenResolver);
            }
        }

        protected override bool CanWriteTokenCore(SecurityToken token)
        {
            if (token is SinacorToken)
            {
                return true;
            }
            else
            {
                return base.CanWriteTokenCore(token);
            }
        }

        protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }

            SinacorToken c = token as SinacorToken;
            if (c != null)
            {
                string sessionId = "0";

                writer.WriteStartElement(Constants.CreditCardTokenPrefix, Constants.SinacorTokenName, Constants.SinacorTokenNamespace);
                writer.WriteAttributeString(Constants.WsUtilityPrefix, Constants.Id, Constants.WsUtilityNamespace, token.Id);
                writer.WriteElementString(Constants.CompanyIdElementName, Constants.SinacorTokenNamespace, c.UserInfo.CompanyId.ToString());
                writer.WriteElementString(Constants.PasswordElementName, Constants.SinacorTokenNamespace, c.UserInfo.Password);
                writer.WriteElementString(Constants.UserNameElementName, Constants.SinacorTokenNamespace, c.UserInfo.UserName);
                writer.WriteElementString(Constants.TokenIdElementName, Constants.SinacorTokenNamespace, c.UserInfo.TokenId);

                if (c.UserInfo.SessionId != null)
                    sessionId = c.UserInfo.SessionId.Value.ToString();
                writer.WriteElementString(Constants.SessionIdElementName, Constants.SinacorTokenNamespace,sessionId);

                if (c.UserInfo.SessionExpires != null)
                    writer.WriteElementString(Constants.SessionExpiresElementName, Constants.SinacorTokenNamespace, c.UserInfo.SessionExpires.ToString());
                else
                    writer.WriteElementString(Constants.SessionExpiresElementName, Constants.SinacorTokenNamespace, true.ToString());

                writer.WriteEndElement();
                writer.Flush();
            }
            else
            {
                base.WriteTokenCore(writer, token);
            }
        }
    }

}
